package com.github.llyb120.tools.ctrl;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.github.llyb120.json.Json;
import com.github.llyb120.json.Obj;
import com.ldsb.moudle.gather.Context;
import lombok.Builder;
import lombok.Data;
import org.bouncycastle.cert.ocsp.Req;
import org.bouncycastle.util.encoders.Base64;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.servlet.ServletResponse;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors;

import static com.github.llyb120.json.Json.ba;
import static com.github.llyb120.json.Json.o;

@Controller
@RequestMapping("/api/tools/groovy-maker")
public class GroovyMakerController {


    private List<String> fields = Json.parse("[\"lotId\",\"dateCode\",\"packageId\",\"qty\",\"lotIdType\",\"customerBill\",\"companyName\",\"parentId\",\"level\",\"templateName\",\"relatedObjId\",\"ATTRIBUTE1\",\"ATTRIBUTE2\",\"ATTRIBUTE3\",\"ATTRIBUTE4\",\"ATTRIBUTE5\",\"ATTRIBUTE6\",\"ATTRIBUTE7\",\"ATTRIBUTE8\",\"ATTRIBUTE9\",\"ATTRIBUTE10\",\"ATTRIBUTE11\",\"ATTRIBUTE12\",\"ATTRIBUTE13\",\"ATTRIBUTE14\",\"ATTRIBUTE15\",\"itemCode\",\"extendPropC1\",\"extendPropC2\",\"extendPropC3\",\"extendPropC4\",\"extendPropC7\",\"extendPropC5\",\"extendPropC6\",\"extendPropC10\"]");

    @Data
    public static class Item {
        String name;
        int start;
        int end;
        int pos;
    }

    @Builder
    @Data
    public static class CodeResult {
        String script;
        String fn;
        String vf;
    }

    @Data
    public static class Request {
        String name;
        String packageName;
        String splitCode;
        String qrCode;
        List<Item> list = new ArrayList<>();


        public String getName() {
            if (StrUtil.isBlank(name)) {
                return "";
            }
            return name.substring(0, 1).toUpperCase() + name.substring(1, name.length());
        }
    }


    private CodeResult makeCodeResult(Request request) {
        //生成入口文件
        StringJoiner sj = new StringJoiner("\n");
        sj.add(String.format("package %s", request.getPackageName()));
        sj.add("");
        sj.add("import com.ldsb.moudle.gather.DefaultExpression");
        sj.add("import com.ldsb.moudle.gather.GatherExpression");
        sj.add("");
        sj.add("DefaultExpression exp=new DefaultExpression();");
        sj.add("if(context.getType()==GatherExpression.PARSER){");
        sj.add(String.format("\texp.parser=new %sFnExpress();", request.getName()));
        sj.add("}else if(context.getType()==GatherExpression.VALIDATE){");
        sj.add(String.format("\texp.validater=new %sVfExpress();", request.getName()));
        sj.add("}");
        sj.add("exp.evaluate(context)");
        String script = sj.toString();
        //fnExpression
        sj = new StringJoiner("\n");
        sj.add(String.format("package %s", request.getPackageName()));
        sj.add("");
        sj.add("import com.ldsb.moudle.gather.parser.ParseContext\n" +
                "import com.vtradex.rf.common.exception.RfException");
        sj.add("import com.vtradex.wms.server.utils.Strings;\n");
        sj.add(String.format("public class %sFnExpress extends BaseFnExpress {", request.getName()));
        sj.add("");
        sj.add(String.format("public String getValue(ParseContext context,int index){\n" +
                "\t\tString[] arr =context.get(\"values\");\n" +
                "\t\tif(arr==null){\n" +
                "\t\t\tString erWeiMa = context.get(\"erWeiMaInfo\");\n" +
                "\t\t\tSystem.out.println(erWeiMa);\n" +
                "\t\t\tif(Strings.isBlank(erWeiMa)){\n" +
                "\t\t\t\tthrow new RfException(\"二维码信息为空,请确认！\");\n" +
                "\t\t\t}\n" +
                "\t\t\tarr = erWeiMa.split(\"%s\");\n" +
                "\t\t\tcontext.set(\"values\", arr);\n" +
                "\t\t}\n" +
                "\t\treturn arr[index] ;\n\t}", request.getSplitCode()).replace("*", "\\\\*"));
        sj.add("");
        //补充字段
        for (Item item : request.getList()) {
            if (fields.contains(item.getName())) {
                sj.add("@Override");
                sj.add(String.format("public Object %s(ParseContext context) {", item.getName()));
                sj.add(String.format("\tString value = getValue(context, %d);", item.getPos()));
//                String value = null;
//                if (StrUtil.isBlank(value)) {
//                    value = "";
//                }
//                int start = item.getStart();
//                int end = item.getEnd();
//                if(start < 0){
//                    start = value.length() - start;
//                }
//                if(end <= 0){
//                    end = value.length() - end;
//                }
//                return value.substring(start, end);
                sj.add(String.format("                if (Strings.isBlank(value)) {\n" +
                        "                    value = \"\";\n" +
                        "                }\n" +
                        "                int start = %d;\n" +
                        "                int end = %d;\n" +
                        "                System.out.println(value);\n" +
                        "                if(start < 0){\n" +
                        "                    start = value.length() - start;\n" +
                        "                }\n" +
                        "                if(end <= 0){\n" +
                        "                    end = value.length() - end;\n" +
                        "                }\n" +
                        "                return value.substring(start, end);\n", item.getStart(), item.getEnd()));
                sj.add("}\n");
            }
        }
        List<Item> others = request.getList().stream()
                .filter(e -> {
                    return !fields.contains(e.getName());
                })
                .collect(Collectors.toList());
        if (!others.isEmpty()) {
            sj.add("@Override");
            sj.add("public Object otherAttribute(String name, ParseContext context) {");
            for (Item item : others) {
                sj.add(String.format("if(\"%s\".equals(name)){", item.getName()));
                sj.add(String.format("\tString value = getValue(context, %d);", item.getPos()));
                sj.add(String.format("                if (Strings.isBlank(value)) {\n" +
                        "                    value = \"\";\n" +
                        "                }\n" +
                        "                int start = %d;\n" +
                        "                int end = %d;\n" +
                        "                if(start < 0){\n" +
                        "                    start = value.length() - start;\n" +
                        "                }\n" +
                        "                if(end <= 0){\n" +
                        "                    end = value.length() - end;\n" +
                        "                }\n" +
                        "                return value.substring(start, end);\n", item.getStart(), item.getEnd()));
                sj.add("}");
            }
            sj.add("return super.otherAttribute(name, context);");
            sj.add("}");
            sj.add("");
        }
        sj.add("}");
        String fn = sj.toString();
        //vfExpression
        sj = new StringJoiner("\n");
        sj.add(String.format("package %s", request.getPackageName()));
        sj.add("");
        sj.add(String.format("public class %sVfExpress extends BaseVfExpress {", request.getName()));
        sj.add("}");
        String vf = sj.toString();

        return CodeResult.builder()
                .script(script)
                .fn(fn)
                .vf(vf)
                .build();
    }


    @RequestMapping("test")
    @ResponseBody
    public Object test(
            @RequestBody Request request
    ) {
        byte[] bs = Base64.decode(request.getQrCode().substring(request.getQrCode().indexOf("base64,")+"base64,".length()));
        String base = QrCodeUtil.decode(new ByteArrayInputStream(bs));
        CodeResult code = makeCodeResult(request);
        try {
            ScriptEngineManager factory = new ScriptEngineManager();
            ScriptEngine engine = factory.getEngineByName("groovy");
            Bindings bindings = engine.createBindings();
            bindings.put("context", new Context(0, request, base));
//            bindings.put("miao", param2);
            engine.eval(code.getFn());
            engine.eval(code.getVf());
            Object result = engine.eval(code.getScript(), bindings);
            if (result == null) {
                return null;
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @RequestMapping("make")
    public HttpEntity make(
            @RequestBody Request request
    ) {
        File dir = new File(System.getProperty("java.io.tmpdir"), IdUtil.objectId());
        dir.mkdirs();

        CodeResult code = makeCodeResult(request);

        FileUtil.writeString(code.getScript(), new File(dir, String.format("%sExpression.groovy", request.getName())), StandardCharsets.UTF_8);
        FileUtil.writeString(code.getFn(), new File(dir, String.format("%sFnExpress.groovy", request.getName())), StandardCharsets.UTF_8);
        FileUtil.writeString(code.getVf(), new File(dir, String.format("%sVfExpress.groovy", request.getName())), StandardCharsets.UTF_8);

        File target = new File(System.getProperty("java.io.tmpdir"), IdUtil.objectId() + ".zip");
        ZipUtil.zip(dir.getAbsolutePath(), target.getAbsolutePath());

        try {
            return new ResponseEntity(FileUtil.readBytes(target), HttpStatus.OK);
        } finally {
            FileUtil.del(dir);
            FileUtil.del(target);
        }
    }
}
